package org.wdm.beans;

import java.util.*;
import org.wdm.beans.points.BusStopPoint;
import org.wdm.beans.points.Point;

/**
 *
 * @author thanasis
 */
public class Step {

    private static final double METERS_TO_MILES = 0.000621371192;
    private String travelMode;
    private double distance;
    private int duration;
    private String instructions;
    private Point start;
    private Point end;
    private List<Crime> crimesList;
    private BoundingBox boundingBox;
    private double criminalityScore;
    private Crime mostFrequentCrime;

    public Step() {
        this.crimesList = new ArrayList<Crime>();
        this.boundingBox = new BoundingBox();
    }

    public Step(String travelMode, double distance, String unit, int duration, String instructions, Point start, Point end) {
        this.travelMode = travelMode;
        if (unit.equalsIgnoreCase("meters")) {
            this.distance = distance * METERS_TO_MILES;
        } else {
            this.distance = distance;
        }
        this.duration = duration;
        this.instructions = instructions;
        this.start = start;
        this.end = end;
        this.crimesList = new ArrayList<Crime>();
        this.boundingBox = new BoundingBox(new Point(start.getLatitude(), start.getLongitude()), new Point(end.getLatitude(), end.getLongitude()));
    }

    public List<Crime> getCrimesList() {
        return crimesList;
    }

    public double getDistance() {
        return distance;
    }

    public int getDuration() {
        return duration;
    }

    public Point getEnd() {
        return end;
    }

    public String getInstructions() {
        return instructions;
    }

    public Point getStart() {
        return start;
    }

    /**
     * @param distance the distance to set
     */
    public void setDistance(double distance) {
        this.distance = distance;
    }

    public double getDistanceInMiles() {
        return distance * METERS_TO_MILES;
    }

    public void setDistanceInMiles(double miles) {
        this.distance = miles / METERS_TO_MILES;
    }

    /**
     * @param duration the duration to set
     */
    public void setDuration(int duration) {
        this.duration = duration;
    }

    /**
     * @param instructions the instructions to set
     */
    public void setInstructions(String instructions) {
        this.instructions = instructions;
    }

    /**
     * @param start the start to set
     */
    public void setStart(Point start) {
        this.start = start;
    }

    /**
     * @param end the end to set
     */
    public void setEnd(Point end) {
        this.end = end;
    }

    /**
     * @param crimesList the crimesList to set
     */
    public void setCrimesList(List<Crime> crimesList) {
        this.crimesList = crimesList;
    }

    public void addCrimes(List<Crime> crimes) {
        crimesList.addAll(crimes);
    }

    public void addCrime(Crime crime) {
        if (this.contains(crime.getCords())) {
            crimesList.add(crime);
        }
    }

    @Override
    public String toString() {
        if (start instanceof BusStopPoint && end instanceof BusStopPoint) {
            return "[" + start.getLatitude() + ", " + start.getLongitude() + "] " + "[" + end.getLatitude() + ", " + end.getLongitude() + "] " + "busRoute=" + ((BusStopPoint) start).getBusRoute() + " travelMode=" + travelMode + ", distance=" + distance + ", duration=" + duration + ", crimes #: " + crimesList.size() + ", criminality score: " + criminalityScore;
        }
        return "[" + start.getLatitude() + ", " + start.getLongitude() + "] " + "[" + end.getLatitude() + ", " + end.getLongitude() + "] " + "travelMode=" + travelMode + ", distance=" + distance + ", duration=" + duration + ", crimes #: " + crimesList.size() + ", criminality score: " + criminalityScore;
    }

    /**
     * @return the travelMode
     */
    public String getTravelMode() {
        return travelMode;
    }

    /**
     * @param travelMode the travelMode to set
     */
    public void setTravelMode(String travelMode) {
        this.travelMode = travelMode;
    }

    /**
     * @return the boundingBox
     */
    public BoundingBox getBoundingBox() {
        return boundingBox;
    }

    /**
     * @param boundingBox the boundingBox to set
     */
    public void setBoundingBox(BoundingBox boundingBox) {
        this.boundingBox = boundingBox;
    }

    public void setBoundingBox(Point start, Point end) {
        this.boundingBox = new BoundingBox(start, end);
    }

    public boolean contains(Point point) {
        return this.boundingBox.contains(point);
    }

    public Point getCenter() {
        return this.boundingBox.getCenterPoint();
    }

    public double getCriminalityScore() {
        return criminalityScore;
    }

    public void setCriminalityScore(double criminalityScore) {
        this.criminalityScore = criminalityScore;
    }

    public Crime getMostFrequentCrime() {
        if (mostFrequentCrime == null) {
        	String mostFrequentCategory = "";
            Map<String, Integer> map = new HashMap<String, Integer>();
            map.put("burglary", 0);
            map.put("anti-social-behaviour", 0);
            map.put("robbery", 0);
            map.put("vehicle-crime", 0);
            map.put("violent-crime", 0);
            map.put("public-disorder-weapons", 0);
            map.put("shoplifting", 0);
            map.put("criminal-damage-arson", 0);
            map.put("other-theft", 0);
            map.put("drugs", 0);
            map.put("other-crime", 0);
            
            HashMap<String, Crime> crimesMap = new HashMap<String, Crime>();

            for (Crime crime : crimesList) {
                String category = crime.getCategory();
                int crimeFreq = map.get(crime.getCategory());
                crimeFreq += 1;
                map.put(category, crimeFreq);
                crimesMap.put(crime.getCategory(),crime);
            }

            int mostFrequent = Integer.MIN_VALUE;
            Iterator<String> iterator = map.keySet().iterator();
            while (iterator.hasNext()) {
                String key = iterator.next();
                int frequency = map.get(key);
                if (frequency > mostFrequent) {
                    mostFrequent = frequency;
                    mostFrequentCategory = key;
                }
            }
            mostFrequentCrime = crimesMap.get(mostFrequentCategory);
        }
        return mostFrequentCrime;
    }
}
